// Project: Salient
// http://salient.codeplex.com
// 
// Copyright 2010, Sky Sanders <sky at skysanders.net>
// Dual licensed under the MIT or GPL Version 2 licenses.
// http://salient.codeplex.com/license
// 
// Date: May 5 2010 

#region

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using mshtml;
using Salient.Net;

#endregion

namespace Salient.Web
{
    ///<summary>
    ///</summary>
    public class HtmlDocument
    {
        #region Properties


        ///<summary>
        ///</summary>
        public CookieContainer Cookies { get; private set; }

        ///<summary>
        ///</summary>
        public HTMLDocumentClass Document { get; private set; }

        ///<summary>
        ///</summary>
        public Exception Exception { get; private set; }

        ///<summary>
        ///</summary>
        public HtmlForm Form
        {
            get
            {
                if (Forms != null && Forms.Count > 0)
                {
                    return Forms[0];
                }
                return null;
            }
        }

        ///<summary>
        ///</summary>
        public List<HtmlForm> Forms { get; private set; }

        ///<summary>
        ///</summary>
        public NameValueCollection Headers { get; private set; }

        ///<summary>
        ///</summary>
        public object PostData { get; private set; }

        ///<summary>
        ///</summary>
        public Uri RequestUri { get; private set; }

        ///<summary>
        ///</summary>
        public string ResponseContentType { get; private set; }

        ///<summary>
        ///</summary>
        public string ResponseText { get; private set; }

        ///<summary>
        ///</summary>
        public Uri ResponseUri { get; private set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// Clears all but cookies
        /// </summary>
        public void Clear()
        {
            Forms = null;
            ResponseText = null;
            ResponseUri = null;
            RequestUri = null;
            PostData = null;
            Headers = null;
            ResponseContentType = null;
            Exception = null;
        }

        ///<summary>
        ///</summary>
        ///<param name="requestUrl"></param>
        ///<param name="postData"></param>
        ///<param name="cookies"></param>
        ///<param name="headers"></param>
        ///<returns></returns>
        public static HtmlDocument CreateGet(string requestUrl, object postData, CookieContainer cookies,
                                                    NameValueCollection headers)
        {
            HtmlDocument page = new HtmlDocument();
            page.Get(requestUrl, postData, cookies, headers);
            return page;
        }

        ///<summary>
        ///</summary>
        ///<param name="requestUrl"></param>
        ///<returns></returns>
        public static HtmlDocument CreateGet(string requestUrl)
        {
            return CreateGet(requestUrl, null, null, null);
        }

        ///<summary>
        ///</summary>
        ///<param name="form"></param>
        ///<param name="cookies"></param>
        ///<param name="headers"></param>
        ///<returns></returns>
        public static HtmlDocument CreatePost(HtmlForm form, CookieContainer cookies, NameValueCollection headers)
        {
            HtmlDocument page = new HtmlDocument();
            page.Post(form, cookies, headers);
            return page;
        }

        ///<summary>
        ///</summary>
        ///<param name="form"></param>
        ///<returns></returns>
        public static HtmlDocument CreatePost(HtmlForm form)
        {
            return CreatePost(form, null, null);
        }

        ///<summary>
        ///</summary>
        ///<param name="requestUrl"></param>
        ///<returns></returns>
        public virtual bool Get(string requestUrl)
        {
            return Get(requestUrl, null, null, null);
        }

        ///<summary>
        ///</summary>
        ///<param name="requestUrl"></param>
        ///<param name="postData"></param>
        ///<param name="cookies"></param>
        ///<param name="headers"></param>
        ///<returns></returns>
        public virtual bool Get(string requestUrl, object postData, CookieContainer cookies, NameValueCollection headers)
        {
            Clear();
            try
            {
                PostData = postData;
                Headers = headers;
                Cookies = cookies ?? (Cookies ?? new CookieContainer());

                HttpWebRequest request = RequestBuilder.Get(requestUrl, PostData, Cookies, Headers);
                RequestUri = request.RequestUri;

                using (WebResponse response = request.GetResponse())
                {
                    ResponseUri = response.ResponseUri;
                    ResponseText = response.GetResponseStream().Text();
                    ResponseContentType = response.ContentType;
                }
            }
            catch (WebException ex)
            {
                WebRequestException wre = WebRequestException.Create(ex);
                Exception = wre;
                return false;
            }

            return ParseForm(ResponseText);
        }



        ///<summary>
        ///</summary>
        ///<param name="responseText"></param>
        ///<returns></returns>
        public bool ParseForm(string responseText)
        {
            try
            {
                Document = new HTMLDocumentClass();
                ((IHTMLDocument2)Document).write(responseText);

                Forms = new List<HtmlForm>();
                IEnumerator enumerator = Document.forms.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    HtmlForm form = new HtmlForm((HTMLFormElement)enumerator.Current);
                    string normalizedUrl = NetworkUtils.NormalizeUrl(ResponseUri.ToString(), form.Action);
                    form.Action = normalizedUrl;
                    Forms.Add(form);
                }
            }
            catch (Exception ex)
            {
                Exception = ex;
                return false;
            }
            return true;
        }

        ///<summary>
        ///</summary>
        ///<param name="form"></param>
        ///<param name="cookies"></param>
        ///<param name="headers"></param>
        ///<returns></returns>
        public virtual bool Post(HtmlForm form, CookieContainer cookies, NameValueCollection headers)
        {
            Clear();

            string url = form.Action;
            //TODO: parse out method,enc-type etc and use a bare .create
            try
            {
                PostData = form.PostData;
                Headers = headers;
                Cookies = cookies ?? (Cookies ?? new CookieContainer());

                HttpWebRequest request = RequestBuilder.PostForm(url, PostData, Cookies, Headers);
                RequestUri = request.RequestUri;

                using (WebResponse response = request.GetResponse())
                {
                    ResponseUri = response.ResponseUri;
                    ResponseText = response.GetResponseStream().Text();
                    ResponseContentType = response.ContentType;
                }
            }
            catch (WebException ex)
            {
                WebRequestException wre = WebRequestException.Create(ex);
                Exception = wre;
                return false;
            }

            return ParseForm(ResponseText);
        }

        ///<summary>
        ///</summary>
        ///<param name="form"></param>
        ///<returns></returns>
        public virtual bool Post(HtmlForm form)
        {
            return Post(form, null, null);
        }

        #endregion

    }
}